using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using BriansClimb.GameObjects;

namespace BriansClimb.DrawableGameObjects.GameScenes
{
    /// <summary>
    /// This is a game component that implements the text menus of the game scenes.
    /// </summary>
    public class TextMenuComponent : DrawableGameComponent
    {
        protected readonly SpriteFont normalFont, selectedFont;
        private readonly StringCollection menuItems;
        protected Vector2 menuPosition = new Vector2();
        protected Color normalColor = Color.White, selectedColor = Color.Red;

        protected AudioManager audioManager;
        protected SpriteBatch spriteBatch = null;
        protected KeyboardState oldKeyboardState;

        protected int selectedItemIndex = 0;
        protected int width, height;

        /// <summary>
        /// Default Constrcutor
        /// </summary>
        /// <param name="game">Main Game Object</param>
        /// <param name="normalFont">Default Font</param>
        /// <param name="selectedFont">Selected Font</param>
        public TextMenuComponent(Game game, SpriteFont normalFont, SpriteFont selectedFont)
            : base(game)
        {
            this.normalFont = normalFont;
            this.selectedFont = selectedFont;
            menuItems = new StringCollection();

            //gets the current sprite batch and audio component
            spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            audioManager = (AudioManager)game.Services.GetService(typeof(AudioManager));

            oldKeyboardState = Keyboard.GetState();

            //setting the initial state of the menu to hidden
            Hide();
        }

        /// <summary>
        /// Width of menu in pixels
        /// </summary>
        public int Width
        {
            get { return width; }
        }

        /// <summary>
        /// Height of menu in pixels
        /// </summary>
        public int Height
        {
            get { return height; }
        }

        /// <summary>
        /// Position of component in screen
        /// </summary>
        public Vector2 Position
        {
            get { return menuPosition; }
            set { menuPosition = value; }
        }

        /// <summary>
        /// Selected menu item index
        /// </summary>
        public int SelectedItemIndex
        {
            get { return selectedItemIndex; }
            set { selectedItemIndex = value; }
        }

        /// <summary>
        /// Shows the text menu component
        /// </summary>
        public void Show()
        {
            this.Visible = true;
            this.Enabled = true;
        }

        /// <summary>
        /// Hides the text menu component
        /// </summary>
        public void Hide()
        {
            //resets the menu to have the 1st option highlighted on next show
            selectedItemIndex = 0;

            this.Visible = false;
            this.Enabled = false;
        }

        /// <summary>
        /// Sets the menu options
        /// </summary>
        /// <param name="items">string array holding the names of the menu options</param>
        public void SetMenuItems(string[] items)
        {
            menuItems.Clear();
            menuItems.AddRange(items);
            CalculateBounds();
        }
        
        /// <summary>
        /// Gets the bounds of the text menu used to center the placement of the text items
        /// </summary>
        protected void CalculateBounds()
        {
            width = 0;
            height = 0;
            foreach (string item in menuItems)
            {
                Vector2 size = selectedFont.MeasureString(item);
                if (size.X > width)
                {
                    width = (int)size.X;
                }
                height += selectedFont.LineSpacing;
            }
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();

            bool down, up;

            // Handle the keyboard
            down = (oldKeyboardState.IsKeyDown(Keys.Down) &&
                (keyboardState.IsKeyUp(Keys.Down)));
            up = (oldKeyboardState.IsKeyDown(Keys.Up) &&
                (keyboardState.IsKeyUp(Keys.Up)));

            //moving the currently highlighted menu down
            if ((down))
            {
                if((this.Enabled)&&(this.Visible))
                    audioManager.PlayCue("btnclick6");
                selectedItemIndex++;

                //menu wraps back to the top
                if (selectedItemIndex == menuItems.Count)
                {
                    selectedItemIndex = 0;
                }
            }
            
            //moving the currently highlighted menu up
            if ((up))
            {
                if((this.Enabled)&&(this.Visible))
                    audioManager.PlayCue("btnclick6");
                selectedItemIndex--;

                //menu wraps back to the bottom
                if (selectedItemIndex == -1)
                {
                    selectedItemIndex = menuItems.Count - 1;
                }
            }

            oldKeyboardState = keyboardState;

            base.Update(gameTime);
        }

        /// <summary>
        /// Allows the game component to draw itself
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of the timing values</param>
        public override void Draw(GameTime gameTime)
        {
            float y = menuPosition.Y;
            for (int i = 0; i < menuItems.Count; i++)
            {
                
                SpriteFont font;
                Color theColor;
                if (i == selectedItemIndex)
                {
                    font = selectedFont;
                    theColor = selectedColor;
                }
                else
                {
                    font = normalFont;
                    theColor = normalColor;
                }

                // Draw the text shadow
                spriteBatch.DrawString(font, menuItems[i],
                    new Vector2(menuPosition.X + 1, y + 1f), Color.Black);
                // Draw the text item
                spriteBatch.DrawString(font, menuItems[i],
                    new Vector2(menuPosition.X, y), theColor);
                y += font.LineSpacing;
            }

            base.Draw(gameTime);
        }
    }
}